home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / arp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  9.7 KB  |  331 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  * mods for WAMPES by DB3FL 1990,1991
  4.  * using ARP_FILE_VERSION 3 from Oct 91 on. Now included the mode of the
  5.  * ax25 connection (stored in "->flags" - same value as defined in iface.h)
  6.  */
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "iface.h"
  12. #include "enet.h"
  13. #include "ax25.h"
  14. #include "icmp.h"
  15. #include "ip.h"
  16. #include "arp.h"
  17. #include "files.h"
  18.  
  19. /* Hash table headers */
  20. struct arp_tab *Arp_tab[HASHMOD];
  21.  
  22. struct arp_stat Arp_stat;
  23.  
  24. static void near arp_output __ARGS((struct iface *iface,int16 hardware,int32 target));
  25.  
  26. /* Send an ARP request to resolve IP address target_ip */
  27. static void near
  28. arp_output(iface,hardware,target)
  29. struct iface *iface;
  30. int16 hardware;
  31. int32 target;
  32. {
  33.         struct arp arp;
  34.         struct mbuf *bp;
  35.         struct arp_type *at = &Arp_type[hardware];
  36.  
  37.         if(iface->output == NULLFP)
  38.                 return;
  39.  
  40.         arp.hardware = hardware;
  41.         arp.protocol = at->iptype;
  42.         arp.hwalen = at->hwalen;
  43.         arp.pralen = sizeof(int32);
  44.         arp.opcode = ARP_REQUEST;
  45.         memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  46.         arp.sprotaddr = iface->addr;
  47.         memset(arp.thwaddr,0,at->hwalen);
  48.         arp.tprotaddr = target;
  49.         if((bp = htonarp(&arp)) == NULLBUF)
  50.                 return;
  51.         (*iface->output)(iface,at->bdcst,
  52.                 iface->hwaddr,at->arptype,bp);
  53.         Arp_stat.outreq++;
  54. }
  55.  
  56. /* Resolve an IP address to a hardware address; if not found,
  57.  * initiate query and return NULLCHAR.  If an address is returned, the
  58.  * interface driver may send the packet; if NULLCHAR is returned,
  59.  * res_arp() will have saved the packet on its pending queue,
  60.  * so no further action (like freeing the packet) is necessary.
  61.  */
  62. char *
  63. res_arp(iface,hardware,target,bp)
  64. struct iface *iface;    /* Pointer to interface block */
  65. int16 hardware;         /* Hardware type */
  66. int32 target;           /* Target IP address */
  67. struct mbuf *bp;        /* IP datagram to be queued if unresolved */
  68. {
  69.     struct arp_tab *arp;
  70.     struct ip ip;
  71.  
  72.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  73.         return arp->hw_addr;
  74.  
  75.     if(arp != NULLARP){
  76.         /* Earlier packets are already pending, kick this one back
  77.          * as a source quench
  78.          */
  79.         ntohip(&ip,&bp);
  80.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  81.         free_p(bp);
  82.     } else {
  83.         /* Create an entry and put the datagram on the
  84.          * queue pending an answer
  85.          */
  86.         arp = arp_add(target,hardware,NULLCHAR,0,0);
  87.         enqueue(&arp->pending,bp);
  88.         arp_output(iface,hardware,target);
  89.     }
  90.     return NULLCHAR;
  91. }
  92. /* Handle incoming ARP packets. This is almost a direct implementation of
  93.  * the algorithm on page 5 of RFC 826, except for:
  94.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  95.  *    pending a reply to our ARP request.
  96.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  97.  * 3. Requests for IP addresses listed in our table as "published" are
  98.  *    responded to, even if the address is not our own.
  99.  */
  100. void
  101. arp_input(iface,bp)
  102. struct iface *iface;
  103. struct mbuf *bp;
  104. {
  105.     struct arp arp;
  106.     struct arp_tab *ap;
  107.     struct arp_type *at;
  108.     int i;
  109.  
  110.     Arp_stat.recv++;
  111.     if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  112.         return;
  113.     if(arp.hardware >= NHWTYPES){
  114.         /* Unknown hardware type, ignore */
  115.         Arp_stat.badtype++;
  116.         return;
  117.     }
  118.     at = &Arp_type[arp.hardware];
  119.     if(arp.protocol != at->iptype){
  120.         /* Unsupported protocol type, ignore */
  121.         Arp_stat.badtype++;
  122.         return;
  123.     }
  124.     if((unsigned)(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  125.         /* Incorrect protocol addr length (different hw addr lengths
  126.          * are OK since AX.25 addresses can be of variable length)
  127.          */
  128.         Arp_stat.badlen++;
  129.         return;
  130.     }
  131.     if(arp.sprotaddr == 0L || arp.tprotaddr == 0L){
  132.         /* We are going to dead-end references for [0.0.0.0], since
  133.          * experience shows that these cause total lock up -- N1BEE
  134.          */
  135.         Arp_stat.badaddr++;
  136.         return;
  137.     }
  138.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  139.         /* This guy is trying to say he's got the broadcast address! */
  140.         Arp_stat.badaddr++;
  141.         return;
  142.     }
  143.  
  144.     /* If this guy is already in the table, update its entry
  145.      * unless it's a manual entry (noted by the lack of a timer)
  146.      */
  147.     ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  148.  
  149.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  150.       && dur_timer(&ap->timer) != 0){
  151.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,0);
  152.     }
  153.  
  154.     /* See if we're the address they're looking for */
  155.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  156.         if(ap == NULLARP)       /* Only if not already in the table */
  157.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,0);
  158.         if(arp.opcode == ARP_REQUEST){
  159.             /* Swap sender's and target's (us) hardware and protocol
  160.              * fields, and send the packet back as a reply
  161.              */
  162.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  163.             /* Mark the end of the sender's AX.25 address
  164.              * in case he didn't
  165.              */
  166.             if(arp.hardware == ARP_AX25)
  167.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  168.  
  169.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  170.             arp.tprotaddr = arp.sprotaddr;
  171.             arp.sprotaddr = iface->addr;
  172.             arp.opcode = ARP_REPLY;
  173.             if((bp = htonarp(&arp)) == NULLBUF)
  174.                 return;
  175.  
  176.             if(iface->forw != NULLIF)
  177.                 iface = iface->forw;
  178.             (*iface->output)
  179.                 (iface,arp.thwaddr,iface->hwaddr,at->arptype,bp);
  180.             Arp_stat.inreq++;
  181.         } else {
  182.             Arp_stat.replies++;
  183.         }
  184.     } else if(arp.opcode == ARP_REQUEST
  185.       && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  186.       && ap->pub){
  187.         /* Otherwise, respond if the guy he's looking for is
  188.          * published in our table.
  189.          */
  190.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  191.         /* Mark the end of the sender's AX.25 address
  192.          * in case he didn't
  193.          */
  194.         if(arp.hardware == ARP_AX25)
  195.             arp.thwaddr[ALEN] |= E;
  196.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  197.         arp.tprotaddr = arp.sprotaddr;
  198.         arp.sprotaddr = ap->ip_addr;
  199.         arp.opcode = ARP_REPLY;
  200.         if((bp = htonarp(&arp)) == NULLBUF)
  201.             return;
  202.         if(iface->forw != NULLIF)
  203.             iface = iface->forw;
  204.         (*iface->output)(iface,arp.thwaddr,iface->hwaddr,at->arptype,bp);
  205.         Arp_stat.inreq++;
  206.     } else if(arp.opcode == RARP_REQUEST){
  207.         for(i=0;i<HASHMOD;i++)
  208.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  209.                 if(memcmp(ap->hw_addr,arp.thwaddr,at->hwalen) == 0)
  210.                     goto found;
  211. found:
  212.         if(ap != NULLARP && ap->pub) {
  213.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  214.             arp.tprotaddr = ap->ip_addr;
  215.             arp.sprotaddr = iface->addr;
  216.             arp.opcode = RARP_REPLY;
  217.             if((bp = htonarp(&arp)) == NULLBUF)
  218.                 return;
  219.             if(iface->forw != NULLIF)
  220.                 iface = iface->forw;
  221.             (*iface->output)(iface,arp.thwaddr,iface->hwaddr,REVARP_TYPE,bp);
  222.             Arp_stat.inreq++;
  223.             }
  224.     }
  225. }
  226.  
  227. /* Add an IP-addr / hardware-addr pair to the ARP table */
  228. struct arp_tab *
  229. arp_add(ipaddr,hardware,hw_addr,pub,flags)
  230. int32 ipaddr;           /* IP address, host order */
  231. int16 hardware;         /* Hardware type */
  232. char *hw_addr;          /* Hardware address, if known; NULLCHAR otherwise */
  233. int pub;                /* Publish this entry? */
  234. int flags;                /* ax25 connection mode */
  235. {
  236.     struct mbuf *bp;
  237.     struct arp_tab *ap;
  238.     struct arp_type *at;
  239.     unsigned hashval;
  240.  
  241.     if(hardware >=NHWTYPES)
  242.         return NULLARP; /* Invalid hardware type */
  243.     at = &Arp_type[hardware];
  244.  
  245.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  246.         /* New entry */
  247.         ap = (struct arp_tab *)mxallocw(sizeof(struct arp_tab));
  248.         ap->hw_addr = mxallocw(at->hwalen);
  249.         ap->timer.func = arp_drop;
  250.         ap->timer.arg = ap;
  251.         ap->hardware = hardware;
  252.         ap->ip_addr = ipaddr;
  253.         ap->hwalen = at->hwalen;
  254.  
  255.         /* Put on head of hash chain */
  256.         hashval = hash_ip(ipaddr);
  257.         ap->prev = NULLARP;
  258.         ap->next = Arp_tab[hashval];
  259.         Arp_tab[hashval] = ap;
  260.         if(ap->next != NULLARP){
  261.             ap->next->prev = ap;
  262.         }
  263.     }
  264.     ap->flags = (ap->hardware == ARP_AX25) ? flags : 0;
  265.  
  266.     if(hw_addr == NULLCHAR){
  267.         /* Await response */
  268.         ap->state = ARP_PENDING;
  269.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  270.     } else {
  271.         /* Response has come in, update entry and run through queue */
  272.         ap->state = ARP_VALID;
  273.         set_timer(&ap->timer,ARPLIFE * 1000L);
  274.         xfree(ap->hw_addr);
  275.         ap->hw_addr = mxallocw(at->hwalen);
  276.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  277.         /* This kludge marks the end of an AX.25 address to allow
  278.          * for optional digipeaters (insert Joan Rivers salute here)
  279.          *
  280.          * changed back to permanent length for use with WNOS routing
  281.          * DB3FL - 1991
  282.          */
  283.         if(hardware == ARP_AX25)
  284.             ap->hw_addr[ALEN] |= E;
  285.         if(pub)                    /* leave published entries as published */
  286.             ap->pub = 1;
  287.  
  288.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  289.             ip_route(NULLIF,NULLIF,bp,0);
  290.     }
  291.     start_timer(&ap->timer);
  292.     return ap;
  293. }
  294.  
  295. /* Remove an entry from the ARP table */
  296. void
  297. arp_drop(p)
  298. void *p;
  299. {
  300.         struct arp_tab *ap = (struct arp_tab *)p;
  301.  
  302.         if(ap == NULLARP)
  303.                 return;
  304.         stop_timer(&ap->timer); /* Shouldn't be necessary */
  305.         if(ap->next != NULLARP)
  306.                 ap->next->prev = ap->prev;
  307.         if(ap->prev != NULLARP)
  308.                 ap->prev->next = ap->next;
  309.         else
  310.         Arp_tab[hash_ip(ap->ip_addr)] = ap->next;
  311.         free_q(&ap->pending);
  312.         xfree(ap->hw_addr);
  313.         xfree((char *)ap);
  314. }
  315.  
  316. /* Look up the given IP address in the ARP table */
  317. struct arp_tab *
  318. arp_lookup(hardware,ipaddr)
  319. int16 hardware;
  320. int32 ipaddr;
  321. {
  322.     struct arp_tab *ap;
  323.  
  324.     for(ap = Arp_tab[hash_ip(ipaddr)]; ap != NULLARP; ap = ap->next){
  325.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  326.              break;
  327.     }
  328.     return ap;
  329. }
  330.  
  331.